#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <boost/filesystem.hpp>
#include <argtable2.h>
#include "biplTypes.h"
#include "buildInFunc.h"

/// Bipl: user function declaration
#include "fn_decls.cxx"

using namespace boost::filesystem;

const char* progname = "fileparser";

typedef std::list<path>::iterator file_t;

class filenameTable {
public:
	filenameTable(int, char* []);
	~filenameTable() {
		/* deallocate each non-null entry in argtable[] */
		arg_freetable(argtable,sizeof(argtable) / sizeof(argtable[0]));
	}
	int check();
	void scan();
	int filter();
private:
	int argc;
	char **argv;
	int nerrors;
	struct arg_file *parseFile;
	struct arg_file *infilenames;
	struct arg_lit  *help;
	struct arg_end  *end;
	void* argtable[4];
	std::vector<path> path_vec;
	std::vector<std::string> exts;
	bool checkExtension(path filename, std::vector<std::string> exts);
public:
	/// vector to store legal file names
	std::list<path> files;
};

int main(int argc, char* argv[])
{
	filenameTable t(argc, argv);
	if (t.check())
		return 1;
	t.scan();
	t.filter();

	#include "begin_block.cxx"
	
	for( file_t iter = t.files.begin(); iter != t.files.end(); iter++)
	{
		//std::cout << iter->string() << std::endl;
		imageTypes _dollar_sign(iter->string());
		{
			/// BODY PART
			#include "body_block.cxx"
		}
	}
	#include "end_block.cxx"
	return 0;
}

bool filenameTable::checkExtension(path filename, std::vector<std::string> exts) {
	for(unsigned int i=0; i < exts.size(); ++i){
		if(filename.extension() == exts[i])
			return true;
	}
	return false;
}


filenameTable::filenameTable(int c, char* v[])
{
	argc = c;
	argv = v;
	nerrors = 0;
	//-----------Command line parsing--------------//
	parseFile = arg_file0("f",NULL,"<dir>", "Input Directory");
	infilenames = arg_filen(NULL,NULL,"<filename>",0,argc+2, "Input file(s)");
	help = arg_lit0(NULL,"help", "print this help and exit");
	end = arg_end(20);
	argtable[0] = parseFile;
	argtable[1] = infilenames;
	argtable[2] = help;
	argtable[3] = end;

	exts.push_back(".jpg");
	exts.push_back(".jpeg");
	exts.push_back(".png");
	exts.push_back(".bmp");
	exts.push_back(".gif");
}

int filenameTable::check()
{	
	if (arg_nullcheck(argtable) != 0)
	{
		/* NULL entries were detected, some allocations must have failed */
		printf("%s: insufficient memory\n", progname);
		/* deallocate each non-null entry in argtable[] */
		arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0]));
		return -1;
	}

	/* set any command line default values prior to parsing */
	parseFile->filename[0] = ".";

	/* Parse the command line as defined by argtable[] */
	nerrors = arg_parse(argc,argv,argtable);

	/* If the parser returned any errors then display them and exit */
	if (nerrors > 0)
	{
		/* Display the error details contained in the arg_end struct.*/
		arg_print_errors(stdout,end,progname);
		printf("Try '%s --help' for more information.\n",progname);
		/* deallocate each non-null entry in argtable[] */
		arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
		return -1;
	}

	if (help->count > 0)
	{
		printf("Usage: %s", progname);
		arg_print_syntax(stdout,argtable,"\n");
		printf("This program demonstrates the use of the image file name parser\n");
		printf("for parsing image files including .jpeg, .jpg, .png, .bmp, .gif \n");
		arg_print_glossary(stdout, argtable,"  %-25s %s\n");
		return 1;
	}
	return 0;
}

void filenameTable::scan()
{
	if (infilenames->count > 0) // No tagged arguments
	{
		for (int i=0; i < infilenames->count; i++)
		{
			path fn = infilenames->filename[i];
			if (!is_regular_file(fn)) {
				std::cout << fn << " is not a filename" << std::endl;
			} 
			else
				path_vec.push_back(infilenames->filename[i]);
		}
	}
	else { // -f tag
		path_vec.push_back(parseFile->filename[0]);   
	}
}

int filenameTable::filter()
{for(std::vector<path>::const_iterator iter = path_vec.begin() ; iter!= path_vec.end(); ++iter)
	{
		path p = *iter;
		try
		{
			if (exists(p))    // does p actually exist?
			{
				if (is_regular_file(p)){        // is p a regular file?
					if(checkExtension(p, exts)){
						//std::cout << p << " size is " << file_size(p) << '\n';
						files.push_back(p);
					}
				} 
				else if (is_directory(p)) {     // is p a directory?
					//cout << p << " is a directory containing:\n";
					std::vector<path> v;                      
					copy(directory_iterator(p), directory_iterator(), back_inserter(v));

					// sort, since directory iteration is not ordered on some file systems
					sort(v.begin(), v.end()); 

					for (std::vector<path>::const_iterator it (v.begin()); it != v.end(); ++it) {
						if(checkExtension(*it, exts)) {
							path fn = *it;
							//std::cout << fn << '\n';
							files.push_back(fn);
						}
					}
				} 
				else
					std::cout << p << " exists, but is neither a regular file nor a directory\n";
			} 
			else
				std::cout << p << " does not exist\n";
		} 
		catch (const filesystem_error& ex) {
			std::cout << ex.what() << '\n';
		}
	}
	return 0;
}


